/**
 * @file drv_led.c
 * @brief 256级灰度三通道LED驱动
 * @author wangh (wanghuan3037@fiberhome.com)
 * @version 1.0
 * @date 2021-01-26
 * @copyright Copyright (c) 2021  烽火通信
 */ 
#include "drv_led.h"
#if (LED_BRIGHTNESS_LEVEL == LED_BRIGHTNESS_256)
#include <string.h>
#include "app_timer.h"

// <0=> Off 
// <1=> Error 
// <2=> Warning 
// <3=> Info 
// <4=> Debug 
#undef NRF_LOG_LEVEL
#define NRF_LOG_LEVEL 3
#include "nrf_log.h"

/** @brief 一个LED的PWM数据结构 */
typedef struct 
{
    uint16_t b1[8];
    uint16_t b2[8];
    uint16_t b3[8];
} __attribute__((packed)) PWM_t;

static PWM_t LED_PWMBuffer[LED_SIZE];   ///< PWM脉冲缓存

APP_TIMER_DEF(led_timer_id);            ///< LED控制定时器
static void led_timer_handler(void * p_context);
APP_TIMER_DEF(led_keep_timer_id);       ///< LED保持定时器（仅用于TM1914）
static void led_keep_timer_handler(void * p_context);


#if LED_DRV_USE_HSV
void RGB2HSV( RGB_t *rgb, HSV_t *pwm )
{
    
}
#endif

/**
 * @brief RGB转换为PWM
 * @param[in]  rgb      RGB颜色
 * @param[out] pwm      PWM波形值
 */
static void RGB2PWM( LedDrv_t *obj, RGB_t *rgb, PWM_t *pwm )
{
    uint8_t mask = 0x80;
    uint8_t i;

    switch (obj->CHIP)
    {
    case TM1914:
    {
        for (i = 0; i < 8; i++)
        {
            pwm->b1[i] = rgb->r & mask ? obj->led_pulse_high : obj->led_pulse_low;
            pwm->b2[i] = rgb->g & mask ? obj->led_pulse_high : obj->led_pulse_low;
            pwm->b3[i] = rgb->b & mask ? obj->led_pulse_high : obj->led_pulse_low;
            mask >>= 1;
        }
    } break;

    default:
    {

    } break;
    }
}



#if (LED_DRV_MODE == LED_DRV_MODE_PWM)
#include "nrf_drv_pwm.h"

static nrf_drv_pwm_t led_pwm = NRF_DRV_PWM_INSTANCE(0); /* pwm 句柄 */

/* pwm 执行序列 */
static nrf_pwm_sequence_t led_pwm_seq =
{
    .values.p_common   = (uint16_t *)LED_PWMBuffer,
    .length         = NRF_PWM_VALUES_LENGTH(LED_PWMBuffer),
    .repeats        = 0,
    .end_delay      = 0
};

static void led_pwm_handler(nrf_drv_pwm_evt_type_t event_type)
{
    if (event_type == NRF_DRV_PWM_EVT_FINISHED)
    {
        // NRF_LOG_INFO("NRF_DRV_PWM_EVT_FINISHED");
    }
}

#elif (LED_DRV_MODE == LED_DRV_MODE_APP_PWM)
#include "app_pwm.h"

APP_PWM_INSTANCE(led_pwm, 1);   /* 创建 led_pwm 句柄使用 TIMER1 */

static volatile bool ready_flag;            // A flag indicating PWM status.

void pwm_ready_callback(uint32_t pwm_id)    // PWM callback function
{
    ready_flag = true;
}

#endif



/**
 * @brief LED驱动初始化
 * @param[in]  obj      LED驱动对象
 * @param[in]  chip     LED驱动芯片型号
 * @param[in]  da       数据线
 * @param[in]  nws      级联个数
 * @return int8_t 
 * - @b Sucess : BSP_SUCCESS \n
 * - @b Fail
 * - @ref BSP_ERROR_INVALID_PARAM - 入参错误
 * - @ref BSP_ERROR_NO_MEM - 内存错误
 */
int8_t led_init( LedDrv_t *obj, LedChip_t chip, uint8_t da, uint8_t nws )
{
    if (obj == NULL)
        return -1;

    obj->CHIP = chip;
    obj->DA = da;
    obj->ws_num = nws;

    if (obj->ws_num > (LED_SIZE))
        obj->ws_num = LED_SIZE;

    switch (obj->CHIP)
    {
    case TM1914:
    {
		
        obj->led_pulse_high = 12;   /* 750us */
        obj->led_pulse_low = 6;     /* 375us */

        /* C1、C2模式设置命令 0xFFFFFA_000005 */
        RGB_t c1 = {0xFF, 0xFF, 0xFF};
        RGB_t c2 = {0x00, 0x00, 0x00};
        RGB2PWM( obj, &c1, &LED_PWMBuffer[0] );
        RGB2PWM( obj, &c2, &LED_PWMBuffer[1] );

        if (obj->ws_num > (LED_SIZE - 2))
            obj->ws_num = LED_SIZE - 2;
    } break;

    default:
    {
        obj->led_pulse_high = 0;
        obj->led_pulse_low = 0;
    } break;
    }

#if (LED_DRV_MODE == LED_DRV_MODE_PWM)
    nrf_drv_pwm_config_t const led_pwm_cfg =
    {
        .output_pins =
        {
            da | NRF_DRV_PWM_PIN_INVERTED,    /* channel 0 NRF_DRV_PWM_PIN_INVERTED (idle state = 1) */
            NRFX_PWM_PIN_NOT_USED,      /* channel 1 */
            NRFX_PWM_PIN_NOT_USED,      /* channel 2 */
            NRFX_PWM_PIN_NOT_USED       /* channel 3 */
        },
        .irq_priority = APP_IRQ_PRIORITY_LOWEST,
        .base_clock   = NRF_PWM_CLK_16MHz,
        .count_mode   = NRF_PWM_MODE_UP,
        .top_value    = 20,
        .load_mode    = NRF_PWM_LOAD_COMMON,    /* 只用一个通道使用公用模式 */
        .step_mode    = NRF_PWM_STEP_AUTO
    };
    APP_ERROR_CHECK(nrf_drv_pwm_init(&led_pwm, &led_pwm_cfg, led_pwm_handler));
#elif (LED_DRV_MODE == LED_DRV_MODE_APP_PWM)
    app_pwm_config_t led_pwm_cfg = APP_PWM_DEFAULT_CONFIG_1CH(2, da);
    // led_pwm_cfg.pin_polarity[0] = APP_PWM_POLARITY_ACTIVE_HIGH;  /* inactive state is low */

    APP_ERROR_CHECK(app_pwm_init(&led_pwm, &led_pwm_cfg, pwm_ready_callback));
    app_pwm_enable(&led_pwm);

#endif

    APP_ERROR_CHECK(app_timer_create(&led_timer_id, APP_TIMER_MODE_REPEATED, led_timer_handler));
    if (obj->CHIP == TM1914)
        APP_ERROR_CHECK(app_timer_create(&led_keep_timer_id, APP_TIMER_MODE_REPEATED, led_keep_timer_handler));

    return 0;
}

static void RGB_Gradual_Step( RGB_t *rgb,  uint8_t step)
{
    /* 渐变步骤：

     */

    /* 黑(0,0,0) --> 红(255,0,0) */
    if ((rgb->r < 0xFF) && (rgb->g == 0) && (rgb->b == 0))
    {
        if (rgb->r + step > 0xFF)
            rgb->r = 0xFF;
        else
            rgb->r += step;
    }
    /* 红(255,0,0) --> 绿(0,255,0) */
    else if ((rgb->g < 0xFF) && (rgb->b == 0))
    {
        if (rgb->g + step > 0xFF)
        {
            rgb->g = 0xFF;
            rgb->r = 0;
        }
        else
        {
            rgb->g += step;
            if (rgb->r > step)
                rgb->r -= step;
            else
                rgb->r = 0;
        }
    }
    /* 绿(0,255,0) --> 蓝(0,0,255) */
    else if ((rgb->r == 0) && (rgb->b < 0xFF))
    {
        if (rgb->b + step > 0xFF)
        {
            rgb->b = 0xFF;
            rgb->g = 0;
        }
        else
        {
            rgb->b += step;
            if (rgb->g > step)
                rgb->g -= step;
            else
                rgb->g = 0;
        }
    }
    /* 蓝(0,0,255) --> 红(255,0,0) */
    else if ((rgb->r < 0xFF) && (rgb->g == 0))
    {
        if (rgb->r + step > 0xFF)
        {
            rgb->r = 0xFF;
            rgb->b = 0;
        }
        else
        {
            rgb->r += step;
            if (rgb->b > step)
                rgb->b -= step;
            else
                rgb->b = 0;
        }
    }
    NRF_LOG_DEBUG("r(%d) g(%d) b(%d)\r\n", rgb->r, rgb->g, rgb->b);
}

/**
 * @brief 计算流水的下一个循环RGB序列
 * @param[in]  obj      LED对象
 */
static void led_next_rgbLoop( LedDrv_t *obj )
{
    if (obj->rgb_loop_num > LED_LOOP_SIZE)
        obj->rgb_loop_num = LED_LOOP_SIZE;

    RGB_t rgb_loop_temp[LED_LOOP_SIZE];

    if (obj->lightMode == LED_WATER_MODE)   /* 流水模式 */
    {
        memcpy(&rgb_loop_temp[0], &obj->rgb_loop[obj->rgb_loop_num-1], sizeof(RGB_t));
        memcpy(&rgb_loop_temp[1], &obj->rgb_loop[0], sizeof(RGB_t) * (obj->rgb_loop_num - 1));
        memcpy(obj->rgb_loop, rgb_loop_temp, sizeof(RGB_t) * obj->rgb_loop_num);
    }
    else if (obj->lightMode == LED_GRADUAL_MODE)    /* 渐变模式 */
    {
        for (uint8_t i=0; i<obj->rgb_loop_num; i++)
            RGB_Gradual_Step( &obj->rgb_loop[i], obj->led_gradual_step );
    }
}

/**
 * @brief 更新 PWM 缓存
 */
static void led_update_PWMBuffer( LedDrv_t *obj )
{
    uint8_t i, j;

    if (obj->CHIP == TM1914)
        memset(&LED_PWMBuffer[2], 0, sizeof(PWM_t)*(LED_SIZE-2));   /* 清空 */
    else
        memset(LED_PWMBuffer, 0, sizeof(PWM_t)*LED_SIZE);

    for (i=0; i<(obj->ws_num / obj->rgb_loop_num); i++)
    {
        for (j = 0; j < obj->rgb_loop_num; j++)
        {
            if (obj->CHIP == TM1914)
                RGB2PWM( obj, &obj->rgb_loop[j], &LED_PWMBuffer[i*obj->rgb_loop_num+j+2] );
            else
                RGB2PWM( obj, &obj->rgb_loop[j], &LED_PWMBuffer[i*obj->rgb_loop_num+j] );
        }
    }
    for (i=0; i<(obj->ws_num % obj->rgb_loop_num); i++)
    {
        if (obj->CHIP == TM1914)
            RGB2PWM( obj, &obj->rgb_loop[i], &LED_PWMBuffer[obj->ws_num - obj->ws_num % obj->rgb_loop_num + i + 2] );
        else
            RGB2PWM( obj, &obj->rgb_loop[i], &LED_PWMBuffer[obj->ws_num - obj->ws_num % obj->rgb_loop_num + i] );
    }
}

/**
 * @brief LED PWM控制的发送
 * @param[in]  obj      LED对象
 */
static void led_send( LedDrv_t *obj )
{
#if (LED_DRV_MODE == LED_DRV_MODE_PWM)
    if (obj->CHIP == TM1914)
        led_pwm_seq.length = (obj->ws_num + 2) * 24;
    else
        led_pwm_seq.length = obj->ws_num * 24;

    // NRF_LOG_INFO("nrf_drv_pwm_simple_playback");
    (void)nrf_drv_pwm_simple_playback(&led_pwm, &led_pwm_seq, 1, NRF_DRV_PWM_FLAG_STOP);
#endif
}

static void led_keep_timer_handler(void * p_context)
{
    LedDrv_t *obj = (LedDrv_t *)p_context;

    led_send( obj );
}

static void led_timer_handler(void * p_context)
{
    LedDrv_t *obj = (LedDrv_t *)p_context;

    if ((obj->lightMode == LED_WATER_MODE) || (obj->lightMode == LED_GRADUAL_MODE))
    {
        led_next_rgbLoop( obj );
        led_update_PWMBuffer( obj );
    }
    else if (obj->lightMode == LED_BLINK_MODE)
    {
        if (obj->led_blink_flag == 0)
        {
            if (obj->CHIP == TM1914)
            {
                RGB_t black_rgb = {0, 0, 0};
                for (uint8_t i=0; i<obj->ws_num; i++)
                    RGB2PWM( obj, &black_rgb, &LED_PWMBuffer[i+2] );
            }
            obj->led_blink_flag = 1;
        }
        else
        {
            led_update_PWMBuffer( obj );
            obj->led_blink_flag = 0;
        }
    }

    led_send( obj );
}

/**
 * @brief LED设置
 * @param[in]  obj      LED对象
 * @param[in]  rgb_loop RGB调色数组
 * @param[in]  rgb_loop_num RGB调色数组长度
 * @param[in]  mode     点灯模式
 * @param[in]  step     渐变步长
 * @param[in]  speed    变化速率（ms）
 * @return int8_t 0：成功，-1：失败
 */
int8_t led_set( LedDrv_t *obj, RGB_t *rgb_loop, uint8_t rgb_loop_num, LightMode_t mode, uint8_t step, uint16_t speed)
{
    if ((obj == NULL) || (rgb_loop == NULL))
        return -1;

    if (rgb_loop_num > LED_LOOP_SIZE)
        return -1;
    
    if (speed < 10)
        speed = 10;

    obj->rgb_loop_num = rgb_loop_num;
    memcpy(obj->rgb_loop, rgb_loop, sizeof(RGB_t)*rgb_loop_num);
    obj->lightMode = mode;

    app_timer_stop(led_timer_id);
    if (obj->CHIP == TM1914)
        app_timer_stop(led_keep_timer_id);
#if (LED_DRV_MODE == LED_DRV_MODE_PWM)
    nrf_drv_pwm_stop( &led_pwm, true);
#endif

    led_update_PWMBuffer( obj );
    led_send( obj );

    if (obj->CHIP == TM1914)
    {
        if (mode == LED_KEEP_MODE)
            app_timer_start(led_keep_timer_id, APP_TIMER_TICKS(300), obj);   /* TM1914寄存器只维持300ms */
        else if (speed > 300)
            app_timer_start(led_keep_timer_id, APP_TIMER_TICKS(300), obj);   /* TM1914寄存器只维持300ms */
    }

    if (mode == LED_BLINK_MODE)         /* 闪烁 */
    {
        app_timer_start(led_timer_id, APP_TIMER_TICKS(speed), obj);
    }
    else if (mode == LED_WATER_MODE)    /* 流水 */
    {
        app_timer_start(led_timer_id, APP_TIMER_TICKS(speed), obj);
    }
    else if (mode == LED_GRADUAL_MODE)  /* 渐变 */
    {
        obj->led_gradual_step = step;
        obj->rgb_loop_num = LED_LOOP_SIZE;
        memset(obj->rgb_loop, 0, sizeof(RGB_t)*obj->rgb_loop_num);
        app_timer_start(led_timer_id, APP_TIMER_TICKS(speed), obj);
    }

    return 0;
}




#endif  /* DRV_LED_EN */

/*********** (C) COPYRIGHT 2021 FiberHome *****END OF FILE****/
